package com.example.demo.Serializer;

import com.example.demo.CustomAnnotations.CustomAnnotation;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/*
 * @Author:大力王
 * @Date:2024/4/11-11-18:08
 * 开始了
 */

/**
 * &#064;Component 放到容器里面
 * &#064;Aspect 拦截---->(标记是一个aop切面)
 * &#064;Slf4j 日志注解
 * &#064;Resource 注入
 * &#064;Around 拦截------>(环绕通知 可以写全路径)
 */
@Component
@Aspect
@Slf4j
public class RedisCachingAspect {

    @Resource
    private RedisTemplate<String,Object> redisTemplate;

    @Around("@annotation(com.example.demo.CustomAnnotations.CustomAnnotation)")
    public Object cacheAroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        //------------------------------获取注解的参数开始-----------------------------------------
        //获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取方法对象
        Method method = signature.getMethod();
        //通过方法对象，获取方法上携带的注解
        CustomAnnotation annotation = method.getAnnotation(CustomAnnotation.class);
        //获取自定义注解的参数
        long ttl = annotation.ttl();
        String group = annotation.group();

        //------------------------------获取注解的参数结束------------------------------------------
        //------------------------------通过现有条件拼接一个唯一key 开始-----------------------------------------
        String key = getCacheKey(group,signature,joinPoint);
        log.info("运行到这里了");
        log.info("key{}",key);
        //------------------------------通过现有条件拼接一个唯一key 结束------------------------------------------

        //------------------------------判断redis是否有这个key 开始-----------------------------------------
        if(Boolean.TRUE.equals(redisTemplate.hasKey(key))){
            log.info("查询缓存逻辑");
            //把json字符串转换成对应的对象
            Gson gson = new Gson();
            return gson.fromJson(Objects.requireNonNull(redisTemplate.opsForValue().get(key)).toString(),method.getReturnType());
        }
        //------------------------------判断redis是否有这个key 结束-----------------------------------------

        //proceed原方法的返回值
        Object result = joinPoint.proceed();
        //----------------------------------在redis里面保存一个------------------------------------
        if(ttl > 0){
            log.info("设置缓存逻辑");
            redisTemplate.opsForValue().set(key,result,ttl, TimeUnit.MILLISECONDS);
        }else{
            redisTemplate.opsForValue().set(key,result);
        }
        log.info("数据库逻辑");
        return result;
    }

    //用来生成一个key
    public String getCacheKey(String group,MethodSignature methodSignature, JoinPoint joinPoint){
        //分组拼接上参数
        //注解分组 + 方法名 + 参数
        log.info("到这儿了：---->getCacheKey");
        return group + methodSignature.getName() + ":" + Arrays.toString(joinPoint.getArgs());
    }
}
